package com.ouc.eddyAlgorithm.controller;

import com.ouc.common.core.domain.AjaxResult;
import com.ouc.common.entity.NcGridData;
import com.ouc.common.ncRead.NcDao;
import com.ouc.common.utils.Arith;
import com.ouc.common.utils.MathUtils;
import com.ouc.eddyAlgorithm.domain.OUCAjaxResult;
import com.ouc.eddyAlgorithm.entity.EddyCenterData;
import com.ouc.eddyAlgorithm.service.EddyAlgorithmCenterService;
import com.ouc.visualization.service.NcService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import ucar.ma2.InvalidRangeException;
import ucar.nc2.NetcdfFile;

import java.io.IOException;

@RestController
@RequestMapping("eddyCenter")
public class EddyCenterController {

  @Autowired
  NcService ncService;

  @Autowired
  NcDao ncDao;

  @Autowired
  private EddyAlgorithmCenterService eddyCenterService;

  private static String CURRENT = "current";

  /**
   * 获取涡旋中心点三维结构的数据
   * 变量名为“current”,则返回流速数据
   * 深度限制条件。若为null，或为空值，默认返回全部层级数据
   * 若经度间隔与纬度间隔不一致，取较大值
   *
   * @param variableName  变量名
   * @param eddyCenterLon 涡旋中心点经度
   * @param eddyCenterLat 涡旋中心点纬度
   * @param eddyRadius    涡旋半径,单位为格网点
   * @param scale         获取涡旋数据扩展范围，单位为格网点，默认为4，即两个格网点
   * @param startLevel    起始层级，可不传
   * @param endLevel      终止层级，可不传
   * @return
   */
  @GetMapping("eddyCenterData")
  public AjaxResult eddyCenterData1(@RequestParam("filePath") String filePath,
                                    @RequestParam("variableName") String variableName,
                                    @RequestParam("eddyCenterLon") float eddyCenterLon,
                                    @RequestParam("eddyCenterLat") float eddyCenterLat,
                                    @RequestParam("eddyRadius") float eddyRadius,
                                    @RequestParam(value = "scale", defaultValue = "4", required = false) Integer scale,
                                    @RequestParam(value = "startLevel", required = false) Integer startLevel,
                                    @RequestParam(value = "endLevel", required = false) Integer endLevel) throws IOException, InvalidRangeException {
    NetcdfFile ncFile = NetcdfFile.open(filePath);
    NcGridData ncGridData = ncDao.getNcGridData(ncFile, variableName.equals(CURRENT) ? "uu" : variableName);
    float interval = (float) Math.max(Arith.round(MathUtils.subtractOfAbs(ncGridData.getListLon()[1], ncGridData.getListLon()[0]), 4),
        Arith.round(MathUtils.subtractOfAbs(ncGridData.getListLat()[1], ncGridData.getListLat()[0]), 4));
    Float[] lon = {eddyCenterLon - (eddyRadius + scale) * interval, eddyCenterLon + (eddyRadius + scale) * interval};
    Float[] lat = {eddyCenterLat - (eddyRadius + scale) * interval, eddyCenterLat + (eddyRadius + scale) * interval};
    Integer[] level = {startLevel, endLevel};

    return getEddyCenterDataByLimit(ncFile, variableName, lon, lat, level);
  }


  /**
   * 获取涡旋中心点三维结构的数据
   * 变量名为“uv”,则返回流速数据
   * 深度限制条件。若为null，或为空值，默认返回全部层级数据
   *
   * @param filename     文件名
   * @param variableName 变量名
   * @param lon          经度限制条件
   * @param lat          纬度限制条件
   * @param level        深度限制条件。若为null，或为空值，默认返回全部层级数据
   * @return
   */
  private OUCAjaxResult getEddyCenterData(String filename, String variableName, Float[] lon, Float[] lat, @Nullable Integer[] level) {
    try {
      if ("uv".equals(variableName)) {
        EddyCenterData uuEddyCenterData = eddyCenterService.getEddyCenterData(filename, "uu", lon, lat, level);
        EddyCenterData vvEddyCenterData = eddyCenterService.getEddyCenterData(filename, "vv", lon, lat, level);
        float[][][] uuValues = uuEddyCenterData.getValues();
        float[][][] vvValues = vvEddyCenterData.getValues();
        float[][][] values = new float[uuValues.length][uuValues[0].length][uuValues[0][0].length];
        for (int i = 0; i < uuValues.length; i++) {
          for (int j = 0; j < uuValues[i].length; j++) {
            for (int k = 0; k < uuValues[i][j].length; k++) {
              if (!Float.isNaN(uuValues[i][j][k])) {
                values[i][j][k] = (float) Math.sqrt(Math.pow(uuValues[i][j][k], 2) + Math.pow(vvValues[i][j][k], 2));
              }
            }
          }
        }
        return OUCAjaxResult.ok(new EddyCenterData(uuEddyCenterData.getLonArr(), uuEddyCenterData.getLatArr(), uuEddyCenterData.getLevelArr(), values));
      } else {
        return OUCAjaxResult.ok(eddyCenterService.getEddyCenterData(filename, variableName, lon, lat, level));
      }
    } catch (Exception e) {
      return OUCAjaxResult.error("数据获取发生异常，请检查参数设置是否有误！！！");
    }
  }

  /**
   * 获取涡旋中心点三维结构的数据
   * 变量名为“current”,则返回流速数据
   * 深度限制条件。若为null，或为空值，默认返回全部层级数据
   *
   * @param ncFile       nc文件
   * @param variableName 变量名
   * @param lon          经度限制条件
   * @param lat          纬度条件
   * @param level        层级
   * @return
   */
  private AjaxResult getEddyCenterDataByLimit(NetcdfFile ncFile, String variableName, Float[] lon, Float[] lat, @Nullable Integer[] level) {
    try {
      if (CURRENT.equals(variableName)) {
        EddyCenterData uuEddyCenterData = eddyCenterService.getEddyCenterDataByLimit(ncFile, "uu", lon, lat, level);
        EddyCenterData vvEddyCenterData = eddyCenterService.getEddyCenterDataByLimit(ncFile, "vv", lon, lat, level);
        float[][][] uuValues = uuEddyCenterData.getValues();
        float[][][] vvValues = vvEddyCenterData.getValues();
        float[][][] values = new float[uuValues.length][uuValues[0].length][uuValues[0][0].length];
        for (int i = 0; i < uuValues.length; i++) {
          for (int j = 0; j < uuValues[i].length; j++) {
            for (int k = 0; k < uuValues[i][j].length; k++) {
              if (!Float.isNaN(uuValues[i][j][k])) {
                values[i][j][k] = (float) Math.sqrt(Math.pow(uuValues[i][j][k], 2) + Math.pow(vvValues[i][j][k], 2));
              }
            }
          }
        }
        return AjaxResult.success(new EddyCenterData(uuEddyCenterData.getLonArr(), uuEddyCenterData.getLatArr(), uuEddyCenterData.getLevelArr(), values));
      } else {
        return AjaxResult.success(eddyCenterService.getEddyCenterDataByLimit(ncFile, variableName, lon, lat, level));
      }
    } catch (Exception e) {
      e.printStackTrace();
      return AjaxResult.error("数据获取发生异常，请检查参数设置是否有误！！！");
    }
  }

  /**
   * 获取等值面数据，找到值在范围内的深度，组成二维数组
   *
   * @param filePath      文件路径
   * @param variableName  变量名
   * @param eddyCenterLon 涡旋中心点经度
   * @param eddyCenterLat 涡旋中心点纬度
   * @param eddyRadius    涡旋半径，往外扩展多少度，默认3度
   * @param standardValue 标准值，这个和interval，应该集合考虑，比如找28-29度的值，那么standardValue设置28.5,interval设置0.5,28.5-0.5，28.5+0.5
   * @param interval      间隔，和标准值差多少
   * @return
   */
  @RequestMapping(value = "getEddyIsosurfaces")
  public AjaxResult getEddyIsosurfaces(@RequestParam("filePath") String filePath,
                                       @RequestParam("variableName") String variableName,
                                       @RequestParam("eddyCenterLon") float eddyCenterLon,
                                       @RequestParam("eddyCenterLat") float eddyCenterLat,
                                       @RequestParam(value = "eddyRadius", defaultValue = "3") float eddyRadius,
                                       @RequestParam(value = "standardValue") float standardValue,
                                       @RequestParam(value = "interval", defaultValue = "0.5") float interval) {
    if (eddyRadius < 0 || interval < 0) {
      return AjaxResult.error(String.format("设置参数有误：eddyRadius:%s,intervsl:%s", eddyRadius, interval));
    }
    Float[] lon = {eddyCenterLon - eddyRadius, eddyCenterLon + eddyRadius};
    Float[] lat = {eddyCenterLat - eddyRadius, eddyCenterLat + eddyRadius};

    try (NetcdfFile ncFile = NetcdfFile.open(filePath)) {
      return AjaxResult.success(eddyCenterService.getNcIsosurfaces(ncFile, variableName, lon, lat, standardValue, interval));
    } catch (Exception e) {
      e.printStackTrace();
      return AjaxResult.error("获取数据失败，请检查输入参数");
    }
  }
}
